package xj.graph2d.tools;

import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.Observer;

import xj.graph2d.BoxGroup;
import xj.graph2d.Command;
import xj.graph2d.DrawShape;
import xj.graph2d.DrawShapeConstants;
import xj.graph2d.GraphComponentShape;
import xj.graph2d.GraphDocument;
import xj.graph2d.GraphNodeBase;
import xj.graph2d.GraphView;
import xj.graph2d.Group;
import xj.graph2d.Label;
import xj.graph2d.command.AddNodeCommand;
import xj.graph2d.command.AddShapeCommand;
import xj.graph2d.command.LabelAuxAction;
import xj.graph2d.command.PasteGroupCommand;
import xj.graph2d.command.SubshapeAuxAction;

public class PasteTool extends SimpleDrawTool {

  public PasteTool() {
  }

  public void startPaste(Observer observer, DrawShape shape) {
    start(observer);
    this.shape = shape;
    if (shape != null && view != null) {
      view.displayHelpMessage(MSGKEY_1);
      Point2D cur = canvas.getMouseLocation();
      if (debug) {
	System.out.println("PasteTool.startPaste(): " + cur);
      }

      if (cur != null) {
	// invoked by short-cut key
	float px = (float) cur.getX();
	float py = (float) cur.getY();
	Point2D p1 = shape.getEnd1();
	float dx = (float) (px - p1.getX());
	float dy = (float) (py - p1.getY());
	shape.move(dx, dy);
	canvas.clearRepaintShapes();
	canvas.addRepaintShape(shape);
	canvas.repaint();
	prev = cur;
      }
    }

  }

  @Override
  public void mouseDragged(Observer observer, Point p, int modifiers) {
    if (debug) {
      System.out.println("PasteTool.mouseDraged(): " + p);
    }

    mouseMoved(observer, p, modifiers);
  }

  @Override
  public void mouseMoved(Observer observer, Point p, int modifiers) {
    if (debug) {
      System.out.println("PasteTool.mouseMoved(): " + p);
    }

    if (shape != null && 
	view != null) {
      displayLocation(p);
      view.displayHelpMessage(MSGKEY_2);
      Point2D cur = view.physicalToVirtual(p);

      if (debug) {
	System.out.println("PasteTool.mouseMoved(): cur=" + cur);
      }

      float px = (float) cur.getX();
      float py = (float) cur.getY();
      float dx = (float) (px - prev.getX());
      float dy = (float) (py - prev.getY());
      shape.moveNotify(dx, dy);
      prev = cur;
      canvas.repaint();
    }
  }

  @Override
  public void mouseLButtonReleased(Observer observer, Point p, int modifiers) {
    if (debug) {
      System.out.println("PasteTool.mouseLButtonReleased(): " + p);
    }

    if (shape != null && 
	view != null) {
      Point2D cur = view.physicalToVirtual(p);
      Command cmd;
      if (shape instanceof BoxGroup) {
	// for handling pasting text boxes,
	// the box is preserved
	if (debug) {
	  System.out.println("PasteTool.mouseLButtonReleased(): @1");
	}

	cmd = new AddShapeCommand(view, doc, shape);
      } else if (shape instanceof Group) {
	// for handling selected (rectangular) boxes,
	// the box is not preserved , individual shapes are pasted
	if (debug) {
	  System.out.println("PasteTool.mouseLButtonReleased(): @2");
	}

	cmd = new PasteGroupCommand(view, doc, (Group) shape);
      } else {
	if (debug) {
	  System.out.println("PasteTool.mouseLButtonReleased(): @3");
	}

	if (graphMode && 
	    doc instanceof GraphDocument && 
	    view instanceof GraphView) {
	  GraphDocument graph = (GraphDocument) doc;
	  GraphView gview = (GraphView) view;
	  if (shape instanceof GraphNodeBase) {
	    GraphNodeBase node = (GraphNodeBase) shape;
	    cmd = new AddNodeCommand(gview, graph, node);
	  } else {
	    cmd = new AddShapeCommand(view, doc, shape);
	    if (shape instanceof Label && 
		(shape.getRole() & ROLE_LABEL) != 0) {
	      Label label = (Label) shape;
	      GraphComponentShape newParent = graph.searchHotSpot(cur);
	      int role = DrawShapeConstants.ROLE_DEFAULT;
	      if (newParent != null) {
		int hotspot = newParent.isOnHotSpot(cur);
		role = GraphComponentShape.hotspotToRole(hotspot);
		Label label1 = newParent.getLabelShape(role);
		newParent.setLabel(role, label);
		if (label1 != null) {
		  doc.shapeRemoved(label1);
		}
		cmd.addAuxAction(new LabelAuxAction(doc, null, newParent,
						    label, label1, -1, role, 
						    LabelAuxAction.ATTACH_LABEL));
	      }
	    }
	  }
	} else {
	  cmd = new AddShapeCommand(view, doc, shape);
	  DrawShape newParent = doc.search(cur, shape);
	  if (newParent != null && 
	      newParent.isAcceptSubshape()) {
	    cmd.addAuxAction(new SubshapeAuxAction(doc, null, newParent, shape,
						   SubshapeAuxAction.ATTACH_SUBSHAPE));
	  }
	}
      }
      doc.executeCommand(cmd);

      canvas.clearRepaintShapes();
      canvas.repaint();

      shape = null;
      view.setSpecialTool(null);
    }
  }

  @Override
  public void mouseEntered(Observer observer, Point p, int modifiers) {
    if (debug) {
      System.out.println("PasteTool.mouseEntered(): " + p);
    }
    if (shape != null && view != null) {
      Point2D cur = view.physicalToVirtual(p);
      if (debug) {
	System.out.println("PasteTool.mouseEntered(): " + cur);
      }

      float px = (float) cur.getX();
      float py = (float) cur.getY();
      Point2D p1 = shape.getEnd1();
      float dx = (float) (px - p1.getX());
      float dy = (float) (py - p1.getY());
      shape.move(dx, dy);
      canvas.clearRepaintShapes();
      canvas.addRepaintShape(shape);
      canvas.repaint();
      prev = cur;
    }
  }

  protected DrawShape shape;

  protected static final String MSGKEY_1 = "PasteTool.message.1";

  protected static final String MSGKEY_2 = "PasteTool.message.2";

  protected static final boolean debug = false;

}
